class_name Pool
#
# The design/intent of this object pool is to be as immutable as possible from the outside.
# With this in mind, I've attempted to not expose many internal to keep things as simple as possible,
# knowing that nothing actually prevents you from modifying the object.
#
# See README.md for example usage
#

# Signal emitted when an object managed by the pool is "killed".
# This is called after the pool has handled the killed signal from the object.

# killed ���ǿ��õġ���������ֵ�˵��

signal killed(target)

# Prefix to use when adding objects to the scene (becomes "undefined_1, undefined_2, etc")
var prefix;# setget,get_prefix;

# Pool total_size on initialization
var total_size;# setget , get_size

# Preloaded scene resource
var scene;# setget , get_scene

# Dictionary of "alive" objects currently in-use.
# Using a dictionary for fast lookup/deletion
var alive = {} 

# Array of "dead" objects currently available for use
var dead = []

# Constructor accepting pool total_size, prefix and scene
func _init(size_, prefix_, scene_):
	total_size = int(size_)
	prefix = str(prefix_)
	scene = scene_

	if false == scene.has_method("is_pool_dead"):
		assert("[Pool]scene need 'is_pool_dead' variant prefix="+prefix);
	if false == scene.has_method("set_pool_dead"):
		assert("[Pool]scene need 'set_pool_dead' variant prefix="+prefix);
	

	init()

# Expand the total pool total_size by the number of total_size objects.
# For example, if passed 2, we will instantiate 2 new objects and add to the dead pool.
func init():
	add_new(total_size)
		
func add_new(add_count):
	if scene == null:
		return

	for i in range(add_count):
		var s = scene.instantiate()
		s.set_name(prefix + "_" + str(i))
		# killed.connect(_on_killed)
		dead.push_back(s)

	total_size += add_count;

func get_prefix():
	return prefix

func get_size():
	return total_size

func get_scene():
	return scene

func get_alive_size():
	return alive.size()

func get_dead_size():
	return dead.size()

# Get the first dead object and make it alive, adding the object to the alive pool and removing from dead pool
func get_one():
	var ds = dead.size()
	if ds > 0:
		var o = dead[ds - 1]
		if !o.is_pool_dead: return null

		var n = o.get_name()
		alive[n] = o
		dead.pop_back()
		o.set_pool_dead(false)
		# o.set_pause_mode(TweenPauseMode.TWEEN_PAUSE_BOUND);
		return o
	else:
		
		var add_count = int(total_size / 2);
		add_count = max(1,add_count);
		print("[Pool]not enough when get_one() ,%s,new_total_size=%d, add count=%d" %[prefix ,total_size ,add_count])
		add_new(add_count);

		var new_one = get_one();
		if new_one:
			return new_one;
		else:
			print("[Pool]Fail after auto add new node.....")
		# 不想在工具类保存外部节点引用，不够了就自己通过初始化的函数自动将创建的
		#节点添加到父节点上去。

	return null
	


# Get the first alive object. Does not affect / change the object's dead value
#func get_first_alive():
	#if alive.total_size() > 0:
		#return alive.values()[0]
#
	#return null

# Convenience method to kill all ALIVE objects managed by the pool
func kill_all():
	for i in alive.values():
		i.kill()

# Attach all objects managed by the pool to the node passed
func add_to_node(node):
	for i in alive.values():
		node.add_child(i)

	for i in dead:
		node.add_child(i)

# Convenience method to show all objects managed by the pool
func show():
	for i in alive.values():
		i.show()

	for i in dead:
		i.show()

# Convenience method to hide all objects managed by the pool
func hide():
	for i in alive.values():
		i.hide()

	for i in dead:
		i.hide()

# Event that all objects should emit so that the pool can manage dead/alive pools
func _on_killed(target):
	# Get the name of the target object that was killed
	var name = target.get_name()

	# Remove the killed object from the alive pool
	alive.erase(name)

	# Add the killed object to the dead pool, now available for use
	dead.push_back(target)

	# target.set_pause_mode(1)

	emit_signal("killed", target)
